﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace MouldingAndMillwork.SSIS
{
    #region CLASS: HashQueue
    /// <summary>
    /// An implementation of a Queue that only permits unique items to exist on it, 
    /// and can be interrogated as to whether a specific item exists on the queue
    /// in a high-performance fashion (O(1) rather than iterating over all elements,
    /// which would be O(n))
    /// </summary>
    /// <typeparam name="K"></typeparam>
    public class HashQueue<K>
    {
        #region Private Variables
        private readonly object _lock = new object();
        private readonly Queue<K> _queue;
        private readonly Hashtable _hashtable;
        #endregion

        #region Constructor
        public HashQueue()
        {
            this._queue = new Queue<K>();
            this._hashtable = new Hashtable();
        }
        #endregion

        #region Properties
        public int Count
        {
            get { lock (this._lock) { return this._queue.Count; } }
        }

        public bool Contains(K key)
        {
            lock (this._lock) { return this._hashtable.Contains(key); }
        }
        #endregion

        #region Methods
        #region Enqueue
        public bool Enqueue(K key)
        {
            lock (this._lock)
            {
                if (!this._hashtable.Contains(key))
                {
                    this._queue.Enqueue(key);
                    this._hashtable.Add(key, true);
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
        #endregion

        #region EnqueueRange
        public int EnqueueRange(IEnumerable keySet)
        {
            int numItemsQueued = 0;

            lock (this._lock)
            {
                foreach (K key in keySet)
                {
                    if (!this._hashtable.Contains(key))
                    {
                        this._queue.Enqueue(key);
                        this._hashtable.Add(key, true);
                        numItemsQueued++;
                    }
                }
            }

            return numItemsQueued;
        }
        #endregion

        #region Dequeue
        public K Dequeue()
        {
            lock (this._lock)
            {
                if (this._queue.Count > 0)
                {
                    return this._queue.Dequeue();
                }
            }
            return default(K);
        }
        #endregion
        #endregion
    }
    #endregion
}
